home *** CD-ROM | disk | FTP | other *** search
/ MacWorld 2003 August / MW 8 2003 CD1.iso / Inside Macworld / Product News / gimp-1.2.4.sit / gimp-1.2.4 / plug-ins / perl / examples / PDB < prev    next >
Encoding:
Text File  |  2000-10-01  |  13.6 KB  |  514 lines

  1. #!/usr/bin/perl
  2.  
  3. #BEGIN {$^W=1};
  4.  
  5. use Gimp::Feature qw(perl-5.005 gtk-1.2);
  6. use Gimp (':consts','__','N_');
  7. use Gimp::Fu;
  8. use Gtk;
  9. use Gtk::Gdk;
  10. use Gimp::UI (); # for the logo
  11. use POSIX 'strftime';
  12.  
  13. #Gimp::set_trace(TRACE_ALL);
  14.  
  15. my $ex;        # average font width for default font
  16. my $ey;        # average font height for default font
  17.  
  18. my $window;    # the main window
  19. my $clist;    # the list of completions
  20. my $rlist;    # the results list
  21. my $inputline;    # the input entry
  22. my $result;    # the result entry
  23. my $synopsis;    # the synopsis label
  24. my $statusbar;    # the statusbar
  25. my $cinfo;    # command info
  26.  
  27. my $idle;    # the idle function id
  28.  
  29. my($blurb,$help,$author,$copyright,$date,$type,$args,$results);
  30. my @args;    # the arguments of the current function
  31.  
  32. my @function;    # the names of all functions
  33. my %function;    # the same as hash
  34. my @completion;    # list of completions
  35. my @compdata;    # index completion -> data
  36. my %plugin_info;# function -> [...]
  37.  
  38. sub refresh {
  39.    undef %function;
  40.    @function = Gimp->procedural_db_query("","","","","","","");
  41.    @function{@function}=(1) x @function;
  42.    eval {
  43.       my ($a, $b, $c, $d, $e, $f) = Gimp->plugins_query("");
  44.       for $i (0..$#$a) {
  45.          $plugin_info{$f->[$i]} = [map $_->[$i], $a, $b, $c, $d, $e];
  46.       }
  47.    }
  48. }
  49.  
  50. sub get_words {
  51.    my $text = $inputline->get_text;
  52.    my $i = 0;
  53.    my($p,$idx,$pos);
  54.    my $word;
  55.    my @words;
  56.    substr($text,$inputline->get('text_position'),0,"\0");
  57.    while ($text =~ /("(?:[^"\\]*(?:\\.[^"\\]*)*)")[ ,]*|([^ ,]+)[ ,]*|[ ,]+/g) {
  58.       $word = defined $1 ? $1 : $2;
  59.       if (($p = index($word, "\0")) >= 0) {
  60.          $idx=$i; $pos=$p;
  61.          substr ($word, $p, 1, "");
  62.       }
  63.       $i++;
  64.       push(@words,$word);
  65.    }
  66.    ($idx,$pos,@words);
  67. }
  68.  
  69. sub set_words {
  70.    my $text=shift;
  71.    $text.=" ".join(",",@_) if scalar@_;
  72.    my $pos=index($text,"\0");
  73.    if ($pos) {
  74.       substr($text,$pos,1,"");
  75.       $inputline->set_text($text);
  76.       $inputline->set_position($pos);
  77.    } else {
  78.       $inputline->set_text($text);
  79.    }
  80. }
  81.  
  82. my $last_func;
  83. my $last_arg;
  84.  
  85. my %type2str = (
  86.    &PDB_BOUNDARY    => 'BOUNDARY',
  87.    &PDB_CHANNEL     => 'CHANNEL',
  88.    &PDB_COLOR       => 'COLOR',
  89.    &PDB_DISPLAY     => 'DISPLAY',
  90.    &PDB_DRAWABLE    => 'DRAWABLE',
  91.    &PDB_FLOAT       => 'FLOAT',
  92.    &PDB_IMAGE       => 'IMAGE',
  93.    &PDB_INT32       => 'INT32',
  94.    &PDB_FLOATARRAY  => 'FLOATARRAY',
  95.    &PDB_INT16       => 'INT16',
  96.    &PDB_PARASITE    => 'PARASITE',
  97.    &PDB_STRING      => 'STRING',
  98.    &PDB_PATH        => 'PATH',
  99.    &PDB_INT16ARRAY  => 'INT16ARRAY',
  100.    &PDB_INT8        => 'INT8',
  101.    &PDB_INT8ARRAY   => 'INT8ARRAY',
  102.    &PDB_LAYER       => 'LAYER',
  103.    &PDB_REGION      => 'REGION',
  104.    &PDB_STRINGARRAY => 'STRINGARRAY',
  105.    &PDB_SELECTION   => 'SELECTION',
  106.    &PDB_STATUS      => 'STATUS',
  107.    &PDB_INT32ARRAY  => 'INT32ARRAY',
  108. );
  109.  
  110. sub setheight {
  111.    my($w,$y)=@_;
  112.    $w->set_usize(-1, ($w->style->font->ascent + $w->style->font->descent) * $y);
  113.  
  114. }
  115.  
  116. sub new_cinfo {
  117.    $cinfo->freeze;
  118.    $cinfo->clear;
  119.  
  120.    my $add_split = sub {
  121.       my($t,$n,$d)=@_;
  122.       $d=~s/^(.{40,60})[ \t]*([\{[:\(])/$1\n$2/mg;
  123.       for(split/\n/,Gimp::wrap_text($d,60)) {
  124.          $cinfo->append("",$t,$n,$_);
  125.          $t=$n="";
  126.       }
  127.    };
  128.    
  129.    if($args) {
  130.       $cinfo->append("In:","","","");
  131.       for(@args) {
  132.          $add_split->($type2str{$_->[0]},$_->[1],$_->[2]);
  133.       }
  134.    }
  135.    if($results) {
  136.       $cinfo->append("Out:","","","");
  137.       for(0..$results-1) {
  138.          my($type,$name,$desc)=Gimp->procedural_db_proc_val ($last_func, $_);
  139.          $add_split->($type2str{$type},$name,$desc);
  140.       }
  141.    }
  142.  
  143.    $cinfo->thaw;
  144. }
  145.  
  146. sub set_current_function {
  147.    my $fun = shift;
  148.    return if $last_func eq $fun || !$function{$fun};
  149.    $last_func = $fun;
  150.    $last_arg = 0;
  151.    @args=();
  152.    eval {
  153.       $function{$fun} or die;
  154.       ($blurb,$help,$author,$copyright,$date,$type,$args,$results)=
  155.          Gimp->procedural_db_proc_info($fun);
  156.       $blurb_label->set($blurb);
  157.       for(0..$args-1) {
  158.          push(@args,[Gimp->procedural_db_proc_arg($fun,$_)]);
  159.       }
  160.       new_cinfo;
  161.  
  162.       $help_text->delete_text(0,-1);
  163.       $help_text->insert_text($help,0);
  164.       $author_label->set($author);
  165.       $copyright_label->set($copyright);
  166.       $date_label->set($date);
  167.       eval {
  168.          my ($menupath, $accel, $path, $imagetypes, $mtime) = @{$plugin_info{$fun}};
  169.          $menupath_label->set($menupath);
  170.          $accelerator_label->set($accel);
  171.          $plugin_path_label->set($path);
  172.          $imagetypes_label->set($imagetypes);
  173.          $last_modified_label->set(strftime("%Y-%m-%d %H:%M:%S (%Z)", localtime ($mtime)));
  174.       };
  175.       warn $@ if $@;
  176.    };
  177.    warn $@ if $@;
  178. }
  179.  
  180. sub set_clist {
  181.    $clist->freeze;
  182.    $clist->clear;
  183.    @completion = ();
  184.    @compdata = ();
  185.    while(@_) {
  186.       $clist->append(@_[0]);
  187.       push @completion, shift;
  188.       push @compdata, shift;
  189.    }
  190.    $clist->thaw;
  191. }
  192.  
  193. sub complete_function {
  194.    my $name = shift;
  195.    $name=~s/[-_]/[-_]/g;
  196.    my @matches = eval { sort grep /$name/i,@function };
  197.    if(@matches>1) {
  198.       set_clist map(($_,$_),@matches);
  199.       $synopsis->set(scalar@matches.__" matching functions");
  200.    } else {
  201.       set_clist @matches,@matches;
  202.       $synopsis->set($matches[0].__" (press Tab to complete)");
  203.    }
  204. }
  205.  
  206. sub complete_type {
  207.    my($type,$name,$desc)=@_;
  208.  
  209.    if($type==PDB_IMAGE) {
  210.       set_clist(map(("$$_: ".$_->get_filename,$$_),Gimp->image_list));
  211.    } elsif($type==PDB_LAYER) {
  212.       set_clist(map { my $i = $_; map(("$$_: ".$i->get_filename."/".$_->get_name,$$_),$i->get_layers)} Gimp->image_list);
  213.    } elsif($type==PDB_CHANNEL) {
  214.       set_clist(map { my $i = $_; map(("$$_: ".$i->get_filename."/".$_->get_name,$$_),$i->get_channels)} Gimp->image_list);
  215.    } elsif($type==PDB_DRAWABLE) {
  216.       set_clist(map { my $i = $_; map(("$$_: ".$i->get_filename."/".$_->get_name,$$_),($i->get_layers,$i->get_channels))} Gimp->image_list);
  217.    } elsif ($type==PDB_INT32) {
  218.       if ($name eq "run_mode") {
  219.          set_clist("RUN_NONINTERACTIVE","RUN_NONINTERACTIVE",
  220.                    "RUN_INTERACTIVE","RUN_INTERACTIVE",
  221.                    "RUN_WITH_LAST_VALS","RUN_WITH_LAST_VALS");
  222.       } elsif ($desc=~s/(?::\s*)?{(.*)}.*?$//) {
  223.          $_=$1;
  224.          my @args;
  225.          while(s/^.*?([A-Za-z_-]+)\s*\(\s*(\d+)\s*\)//) {
  226.             push(@args,"$2: $1",$2);
  227.          }
  228.          set_clist(@args);
  229.       } else {
  230.          set_clist;
  231.       }
  232.    } else {
  233.       set_clist;
  234.    }
  235.    $synopsis->set($desc);
  236. }
  237.  
  238. sub update_completion {
  239.    my($idx,$pos,@words)=get_words;
  240.  
  241.    return unless $idx ne $last_arg;
  242.    $last_arg=$idx;
  243.  
  244.    set_current_function $words[0];
  245.  
  246.    if ($idx == 0) {
  247.       complete_function($words[0]);
  248.    } elsif ($idx>@args) {
  249.       $synopsis->set(__"too many arguments");
  250.       set_clist;
  251.    } else {
  252.       complete_type(@{$args[$idx-1]});
  253.    }
  254. }
  255.  
  256. sub do_completion {
  257.    update_completion;
  258.  
  259.    my($idx,$pos,@words)=get_words;
  260.    my($word)=$words[$idx];
  261.  
  262.    $word=~s/[-_]/[-_]/g;
  263.    my(@matches)=grep /$word/i,@completion;
  264.    my $new;
  265.    if (@matches>1) {
  266.       if (join("\n",@matches) =~ ("^(".$words[$idx].".*).*?".("\n\\1.*" x scalar@matches-1))) {
  267.          $new=$1;
  268.       }
  269.    } elsif(@matches==1) {
  270.       $new=$compdata[0];
  271.    } else {
  272.       Gtk::Gdk->beep;
  273.    }
  274.    if (defined $new) {
  275.       $words[$idx]=$new;
  276.       set_current_function $words[0] if $idx==0;
  277.       if($idx<@args) {
  278.          $words[$idx+1]="\0".$words[$idx+1];
  279.       } else {
  280.          $words[$idx].="\0";
  281.       }
  282.       set_words @words;
  283.    }
  284.    undef $last_arg;
  285. }
  286.  
  287. sub execute_command {
  288.    my($idx,$pos,$fun,@args)=get_words;
  289.    $res=eval { Gimp->$fun(@args) };
  290.    if ($@) {
  291.       $statusbar->set($@);
  292.       $result->set_text("");
  293.       Gtk::Gdk->beep;
  294.    } else {
  295.       $statusbar->set('');
  296.       $result->set_text($res);
  297.       $rlist->prepend_items(new Gtk::ListItem $res);
  298.    }
  299. }
  300.  
  301. sub idle {
  302.    Gtk->idle_remove($idle) if $idle;
  303.    undef $idle;
  304.    update_completion;
  305. }
  306.  
  307. sub do_idle {
  308.    $idle=Gtk->idle_add(\&idle) unless $idle;
  309. }
  310.  
  311. eval "use Gtk::Keysyms ()";
  312. $Gtk::Keysyms{Tab} ||= 0xFF09;
  313.  
  314. sub inputline {
  315.    my $e = new Gtk::Entry;
  316.    $e->set_text("");
  317.    $e->signal_connect("changed",sub {
  318.       undef $last_arg;
  319.       do_idle;
  320.    });
  321.    $e->signal_connect("focus_in_event",\&do_idle);
  322.    $e->signal_connect("button_press_event",\&do_idle);
  323.    $e->signal_connect("key_press_event",sub {
  324.       undef $last_arg;
  325.       do_idle;
  326.       if ($_[1]->{keyval} == $Gtk::Keysyms{Tab}) {
  327.           $_[0]->signal_emit_stop_by_name('key_press_event');
  328.          do_completion;
  329.          1;
  330.       } else {
  331.          ();
  332.       }
  333.    });
  334.    $e->signal_connect("activate",\&execute_command);
  335.    #$e->set_usize($ex*40,0);
  336.    $inputline=$e;
  337.  
  338.    my $c = new Gtk::CList(1);
  339.    setheight $c, 6;
  340.    $clist = $c;
  341.    $c->set_selection_mode(-extended);
  342.    $c->signal_connect("select_row", sub {
  343.       eval {
  344.          my($idx,$pos,@words)=get_words;
  345.          $words[$idx]=$compdata[$_[1]]."\0";
  346.          set_words (@words);
  347.          set_current_function (substr($words[0],0,-1)) unless $idx;
  348.       };
  349.       do_idle;
  350.    });
  351.  
  352.    my $r = new Gtk::List;
  353.    $rlist = $r;
  354.    $r->set_selection_mode(-single);
  355.    $r->set_selection_mode(-browse);
  356. }
  357.  
  358. sub info {
  359.    my $info = new Gtk::Dialog;
  360.    $info->set_title(__"Function Info");
  361.    $info->signal_connect(delete_event => sub { $info->hide });
  362.  
  363.    my $close = new Gtk::Button __"Close";
  364.    $close->signal_connect(clicked => sub { $info->hide });
  365.    $info->action_area->add($close);
  366.  
  367.    my $table = new Gtk::Table 2,9+1,0;
  368.    my $y = 0;
  369.    $info->vbox->add($table);
  370.  
  371.    local *add_info = sub {
  372.       my ($label, $widget, $large) = @_;
  373.       $label = new Gtk::Label $label.": ";
  374.       $label->set_alignment(0, 0);
  375.       $table->attach($label,0,1,$y,$y+1,[-fill],[-fill],0,0);
  376.       if ($large) {
  377.          $y++;
  378.          $table->attach($widget,0,2,$y,$y+$large,[-expand,-fill],[-expand,-fill],0,0);
  379.          $y+=$large;
  380.       } else {
  381.          $widget->set_alignment(0, 0);
  382.          $table->attach($widget,1,2,$y,$y+1,[-fill],[-fill],0,0);
  383.          $y++;
  384.       }
  385.    };
  386.  
  387.    $blurb_label = new Gtk::Label;
  388.    add_info(__"Menu Path", $menupath_label = new Gtk::Label);
  389.    add_info(__"Accelerator", $accelerator_label = new Gtk::Label);
  390.    add_info(__"Image Types", $imagetypes_label = new Gtk::Label);
  391.    add_info(__"Author", $author_label = new Gtk::Label);
  392.    add_info(__"Copyright", $copyright_label = new Gtk::Label);
  393.    add_info(__"Date/Version", $date_label = new Gtk::Label);
  394.    add_info(__"Last Modified", $last_modified_label = new Gtk::Label);
  395.    add_info(__"Plug-In Path", $plugin_path_label = new Gtk::Label);
  396.  
  397.    $help_text = new Gtk::Text;
  398.    $help_text->set_editable(0);
  399.    $help_text->set_word_wrap(1);
  400.    my $cs = new Gtk::ScrolledWindow undef,undef;
  401.    $cs->set_policy(-automatic,-automatic);
  402.    $cs->add ($help_text);
  403.    add_info (__"Description", $cs, 2);
  404.  
  405.    my $h = new Gtk::HBox(0,5);
  406.    my $more = new Gtk::Button __"More...";
  407.    $more->signal_connect(clicked => sub { $info->visible ? $info->hide : $info->show_all });
  408.    $h->add($blurb_label);
  409.    $h->add($more);
  410.    $h;
  411. }
  412.  
  413. sub create_main {
  414.    my $b;
  415.    my $t;
  416.  
  417.    $t = new Gtk::Tooltips;
  418.    my $w = new Gtk::Dialog;
  419.    $window = $w;
  420.    $w->realize;
  421.    $ex = $w->style->font->string_width ('Mn')*0.5;
  422.    $ey = $w->style->font->string_width ('My');
  423.  
  424.    $w->set_title(__"PDB Explorer - the olof edition (yet still an alpha version)");
  425.    $w->signal_connect("destroy",sub {main_quit Gtk});
  426.  
  427.    $b = new Gtk::Button __"Close";
  428.    $w->action_area->add($b);
  429.    $b->signal_connect("clicked",sub {main_quit Gtk});
  430.  
  431.    my $vpane = new Gtk::VPaned; $w->vbox->add($vpane);
  432.    $vpane->add1(my $f1 = new Gtk::VBox 0,0);
  433.    $vpane->add2(my $f2 = new Gtk::VBox 0,0);
  434.  
  435.    my $h = new Gtk::HBox (0,5);
  436.    $f1->pack_start ($h,0,0,0);
  437.  
  438.    inputline;
  439.  
  440.    $synopsis = new Gtk::Label "";
  441.    $synopsis->set_justify(-left);
  442.  
  443.    my $table = new Gtk::Table 3,4,0;
  444.    $f1->pack_start($table,1,1,0);
  445.  
  446.    my $cs = new Gtk::ScrolledWindow undef,undef;
  447.    $cs->set_policy(-automatic,-automatic);
  448.    $cs->add ($clist);
  449.    #$cs->set_usize(0,$ey*6);
  450.  
  451.    my $rs = new Gtk::ScrolledWindow undef,undef;
  452.    $rs->set_policy(-automatic,-automatic);
  453.    $rs->add_with_viewport ($rlist);
  454.  
  455.    $result = new Gtk::Entry;
  456.    $result->set_editable(0);
  457.    #$result->set_usize($ex*30,0);
  458.  
  459.    $statusbar = new Gtk::Label;
  460.  
  461.    $table->border_width(10);
  462.  
  463.    $table->attach(new Gtk::Label(__"Synopsis") ,0,1,0,1,{},{},0,0);
  464.       $table->attach($synopsis ,1,2,0,1,{},{},0,0);
  465.          $table->attach(Gimp::UI::logo($w),2,3,0,1,{},{},0,0);
  466.    $table->attach(new Gtk::Label(__"Command")  ,0,1,1,2,{},{},0,0);
  467.       $table->attach($inputline,1,3,1,2,['expand','fill'],{},0,0);
  468. #         $table->attach($result,2,3,1,2,['expand','fill'],{},0,0);
  469.    $table->attach(new Gtk::Label(__"Shortcuts"),0,1,2,3,{},{},0,0);
  470.       $table->attach($cs       ,1,3,2,3,['expand','fill'],['expand','fill'],0,0);
  471. #         $table->attach($rs,2,3,2,3,['expand','fill'],['expand','fill'],0,0);
  472.    $table->attach(new Gtk::Label(__"Status"),0,1,3,4,{},{},0,0);
  473.    $table->attach($statusbar,1,3,3,4,{},{},0,0);
  474.  
  475.    $f2->pack_start(info,0,1,5);
  476.    my $sw = new Gtk::ScrolledWindow;
  477.    $sw->set_policy(-automatic, -automatic);
  478.    $cinfo = new_with_titles Gtk::CList '',__"TYPE",__"NAME",__"DESCRIPTION";
  479.    $cinfo->set_column_auto_resize (0,1);
  480.    $cinfo->set_column_auto_resize (1,1);
  481.    $cinfo->set_column_auto_resize (2,1);
  482.    $cinfo->set_selection_mode('single');
  483.    setheight $cinfo, 8;
  484.    $sw->add ($cinfo);
  485.    $f2->pack_start ($sw,1,1,5);
  486.  
  487.    idle;
  488.  
  489.    $w->realize;
  490.    show_all $w;
  491. }
  492.  
  493. register "extension_pdb_explorer",
  494.          "Procedural Database Explorer",
  495.          "This is a more interactive and less broken / script-fu-centric version of the DB Browser",
  496.          "Marc Lehmann",
  497.          "Marc Lehmann",
  498.          "0.4alpha",
  499.          N_"<Toolbox>/Xtns/PDB Explorer...",
  500.          "",
  501.          [],
  502.          sub {
  503.  
  504.    Gimp::gtk_init;
  505.    refresh;
  506.    create_main;
  507.    main Gtk;
  508.  
  509.    ();
  510. };
  511.  
  512. exit main;
  513.  
  514.